#include "ice_transport_channel.h"
#include "ice/udp_port.h"
#include "ice/ice_connection.h"

#include <rtc_base/logging.h>

namespace xrtc {

IceTransportChannel::IceTransportChannel(EventLoop* el, PortAllocator* allocator, 
                        const std::string& transport_name, IceCandidateComponent component) 
                      : m_el(el), m_transport_name(transport_name), m_component(component)
                      , m_allocator(allocator) {
        RTC_LOG(LS_INFO) << "ice transport channel created, transport_name: " << m_transport_name
        << ", component: " << m_component;
}

// TODO
// IceTransportChannel::~IceTransportChannel() {
//     // 清理UDP端口对象
//     for (auto port : m_udp_ports) {
//         delete port;
//     }
//     m_udp_ports.clear();
// }

void IceTransportChannel::setIceParameters(const IceParameters& ice_parameters) {
    RTC_LOG(LS_WARNING) << "set ice parameters, transport_name: " << m_transport_name
                            << ", component: " << m_component
                            << ", ufrag: " << ice_parameters.m_ice_ufrag
                            << ", pwd: " << ice_parameters.m_ice_pwd;
        
        m_ice_parameters = ice_parameters;
}

void IceTransportChannel::set_remote_ice_params(const IceParameters &ice_parameters)
{
    RTC_LOG(LS_WARNING) << "set remote ice parameters, transport_name: " << m_transport_name
                            << ", component: " << m_component
                            << ", ufrag: " << ice_parameters.m_ice_ufrag
                            << ", pwd: " << ice_parameters.m_ice_pwd;
        
        m_remote_ice_parameters = ice_parameters;
}

// 收集candidate (一个传输地址，由ip、port、protocol构成)
void IceTransportChannel::gathering_candidate() {
    if (m_ice_parameters.m_ice_pwd.empty() || m_ice_parameters.m_ice_ufrag.empty()) {
        RTC_LOG(LS_WARNING) << "cannot gather candidate beacaus ice-ufrag and ice-pwd is empty"
                            << ", transport_name: " << m_transport_name
                            << ", component: " << m_component
                            << ", ufrag: " << m_ice_parameters.m_ice_ufrag
                            << ", pwd: " << m_ice_parameters.m_ice_pwd;
        return ;                            
    }

    // network_list只有一个固定的公网IP地址 (43.139.117.90)
    auto network_list = m_allocator->get_networks();
    if (network_list.empty()) {
        RTC_LOG(LS_WARNING) << "cannot gathering candidate because network_list is empty"
                            << ", transport_name: " << m_transport_name
                            << ", component: " << m_component;
        return;
    }

    for (auto network : network_list) {
        // 创建UDP通道
        UDPPort* port = new UDPPort(m_el, m_transport_name, m_component, m_ice_parameters);
        // 连接UDPPort的signal_unknown_address信号到IceTransportChannel的_on_unknown_address方法
        port->signal_unknown_address.connect(this, &IceTransportChannel::_on_unknown_address);

        Candidate c;
        // 创建Candidate
        int ret = port->create_ice_candidate(network, m_allocator->get_min_port(), m_allocator->get_max_port(), c);
        if (ret != 0) {
            delete port;  // 释放失败时创建的对象
            continue;
        }

        m_local_candidates.push_back(c);
    }

    //  ICE 候选地址收集完成后进行通知, 发送信号
    signal_candidate_allocate_done(this, m_local_candidates);
}

std::string IceTransportChannel::to_string() {
    std::stringstream ss;
    ss << "Channel[" << this << ":" << m_transport_name << ":" << m_component
        << "]";
    return ss.str();
}

// 处理未知地址（客户端还未与服务器交换过Candidate，客户端NAT映射的反射地址）信号, 创建反射地址的Candidate
void IceTransportChannel::_on_unknown_address(UDPPort *port, const rtc::SocketAddress &addr, StunMessage *msg, 
                                              const std::string &remote_ufrag) {
    const StunUInt32Attribute* priority_attr = msg->get_uint32(STUN_ATTR_PRIORITY);
    if (!priority_attr) {
        RTC_LOG(LS_WARNING) << to_string() << ": priority not found in the"
                            << " binding request message, remote_addr: " << addr.ToString();

        // 发送Binding错误响应
        port->send_binding_error_response(msg, addr, STUN_ERROR_BAD_REQUEST,
            STUN_ERROR_REASON_BAD_REQUEST);                    

        return;
    }

    uint32_t remote_priority = priority_attr->get_value();

    // 创建反射地址的Candidate
    Candidate remote_candidate;
    remote_candidate.m_component = m_component;
    remote_candidate.m_protocol = "udp";
    remote_candidate.m_address = addr;
    // remote_candidate.m_port = addr.port();
    remote_candidate.m_username = remote_ufrag;
    remote_candidate.m_password = m_remote_ice_parameters.m_ice_pwd;
    remote_candidate.m_type = PRFLX_PORT_TYPE;
    remote_candidate.m_priority = remote_priority;

    // remote_candidate.m_foundation = compute_foundation(c.m_type, c.m_protocol, "", c.m_address);
    RTC_LOG(LS_INFO) << to_string() << ": create peer reflexive candidate: " << remote_candidate.to_string();

    // 创建ice connection对象
    IceConnection* ice_connection = port->create_connection(remote_candidate);
    if (!ice_connection) {
        RTC_LOG(LS_WARNING) << to_string() << ": create connection from "
                            << " peer reflexive candidate failed, remote_addr: "
                            << addr.ToString();
        
        // 发送Binding错误响应
        port->send_binding_error_response(msg, addr, STUN_ERROR_SERVER_ERROR,
                                STUN_ERROR_REASON_SERVER_ERROR);

        return;
    }
    
    RTC_LOG(LS_INFO) << to_string() << ": create connection from "
                     << " peer reflexive candidate success, remote_addr: " << addr.ToString();
    
    // 处理STUN Binding请求
    ice_connection->handle_stun_binding_request(msg);
}

}